#!/bin/bash

# ====================================================
# Script Name: dump_top.sh
# Description: Dumps process and thread information
#              using ps and top commands.
# ====================================================

# Default variables
DEFAULT_OUTPUT="topdump.txt"
DEFAULT_TOP_ITER=360
DEFAULT_TOP_DELAY=1

# Function: Display usage information
usage() {
    echo "Usage: $0 -p <Process_Name_or_PID> [-o <output_file>] [-n <top_iterations>] [-d <top_delay>] [-h]"
    echo ""
    echo "  -p    Process name or PID to monitor (required)"
    echo "  -o    Output file (default: $DEFAULT_OUTPUT)"
    echo "  -n    Number of top iterations (default: $DEFAULT_TOP_ITER)"
    echo "  -d    Delay between top iterations in seconds (default: $DEFAULT_TOP_DELAY)"
    echo "  -h    Display this help message"
}

# Check if required commands exist
for cmd in ps top grep cut pgrep; do
    if ! command -v $cmd &> /dev/null; then
        echo "Error: $cmd command not found. Please install it first."
        exit 1
    fi
done

# Parse command-line options
while getopts "p:o:n:d:h" opt; do
    case ${opt} in
        p )
            PROCESS_INPUT=$OPTARG
            ;;
        o )
            OUTPUT_FILE=$OPTARG
            ;;
        n )
            TOP_ITER=$OPTARG
            ;;
        d )
            TOP_DELAY=$OPTARG
            ;;
        h )
            usage
            exit 0
            ;;
        \? )
            echo "Invalid Option: -$OPTARG" 1>&2
            usage
            exit 1
            ;;
        : )
            echo "Invalid Option: -$OPTARG requires an argument" 1>&2
            usage
            exit 1
            ;;
    esac
done
shift $((OPTIND -1))

# Check if -p parameter is provided
if [ -z "$PROCESS_INPUT" ]; then
    echo "Error: Process name or PID is required."
    usage
    exit 1
fi

# Set default values if not provided
OUTPUT_FILE=${OUTPUT_FILE:-$DEFAULT_OUTPUT}
TOP_ITER=${TOP_ITER:-$DEFAULT_TOP_ITER}
TOP_DELAY=${TOP_DELAY:-$DEFAULT_TOP_DELAY}

# Determine if PROCESS_INPUT is PID or process name
if [[ "$PROCESS_INPUT" =~ ^[0-9]+$ ]]; then
    PID=$PROCESS_INPUT
    # Retrieve process name using ps -e | grep and cut
    PROCESS_INFO=$(ps -e | grep -w "${PID}" | grep -v grep)
    PROCESS_NAME=$(echo "$PROCESS_INFO" | tr -s ' ' | cut -d ' ' -f5)
    if [ -z "${PROCESS_NAME}" ]; then
        echo "Error: No process found with PID ${PID}."
        exit 1
    fi
else
    PROCESS_NAME=$PROCESS_INPUT
    # Retrieve PID(s) using process name
    PIDS=$(pgrep -x "${PROCESS_NAME}")
    if [ -z "${PIDS}" ]; then
        echo "Error: No process found with name '${PROCESS_NAME}'."
        exit 1
    fi
fi

echo "Starting to record process and thread information for '${PROCESS_NAME}' to ${OUTPUT_FILE}"

# Record ps command output
{
    if [[ "$PROCESS_INPUT" =~ ^[0-9]+$ ]]; then
        echo "=== ps -T -p ${PID} ==="
        ps -T -p ${PID}
    else
        for PID in ${PIDS}; do
            echo "=== ps -T -p ${PID} ==="
            ps -T -p ${PID}
        done
    fi
} > "${OUTPUT_FILE}"

# Record Process_Info section using ps -e | grep
{
    echo ""
    echo "=== Process_Info ==="
    if [[ "$PROCESS_INPUT" =~ ^[0-9]+$ ]]; then
        echo "$PROCESS_INFO"
    else
        for PID in ${PIDS}; do
            PROCESS_INFO=$(ps -e | grep -w "${PID}" | grep -v grep)
            echo "$PROCESS_INFO"
        done
    fi
} >> "${OUTPUT_FILE}"

# Record top command output
{
    echo ""
    echo "=== top -H -b -n ${TOP_ITER} -d ${TOP_DELAY} -p ${PROCESS_INPUT} ==="
    if [[ "$PROCESS_INPUT" =~ ^[0-9]+$ ]]; then
        top -H -b -n ${TOP_ITER} -d ${TOP_DELAY} -p ${PID}
    else
        for PID in ${PIDS}; do
            top -H -b -n ${TOP_ITER} -d ${TOP_DELAY} -p ${PID} &
        done
        wait
    fi
} >> "${OUTPUT_FILE}"

echo "Completed. Output saved to ${OUTPUT_FILE}"
